package jdh.util.db.transacao;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;

@SuppressWarnings("unused")
public class JPAUtil {

	private static JPAUtil me;
	private static EntityManagerFactory entityManagerFactory;
	private static final ThreadLocal<EntityManager> threadEntityManager = new ThreadLocal<EntityManager>();
	private static final ThreadLocal<EntityTransaction> threadTransaction = new ThreadLocal<EntityTransaction>();
	private static final ThreadLocal<Long> threadCount = new ThreadLocal<Long>();

	private JPAUtil() {
		this.init();
	}

	public static JPAUtil getIntance() {
		if (me == null) {
			me = new JPAUtil();
		}
		return me;
	}

	private void init() {
		entityManagerFactory = Persistence
				.createEntityManagerFactory("WebAppTeste");
	}

	public EntityManager getEntityManager() {
		EntityManager entityManager = threadEntityManager.get();
		try {
			if (entityManager == null || !entityManager.isOpen()) {
				entityManager = entityManagerFactory.createEntityManager();
				threadEntityManager.set(entityManager);
			}
		} catch (RuntimeException ex) {
			ex.printStackTrace();
		}
		return entityManager;
	}

	public void beginTransaction() {
		alteraContador(1);
		EntityTransaction entityTransaction = threadTransaction.get();
		try {
			if (entityTransaction == null) {
				entityTransaction = getEntityManager().getTransaction();
				entityTransaction.begin();
				threadTransaction.set(entityTransaction);
				System.out.println("Criou transacao para="
						+ Thread.currentThread().getName());
			} else {
				System.out.println("Nao criou transacao para="
						+ Thread.currentThread().getName());

			}
		} catch (RuntimeException ex) {
			ex.printStackTrace();
		}
	}

	public void closeEntityManager() {
		if (podeComitar()) {
			try {
				EntityManager entityManager = threadEntityManager.get();
				threadEntityManager.set(null);
				if (entityManager != null && entityManager.isOpen()) {
					entityManager.close();
				}

				EntityTransaction entityTransaction = threadTransaction.get();
				if (entityTransaction != null && entityTransaction.isActive()) {
					rollbackTransaction();
					throw new RuntimeException("EntityManager sendo fechado "
							+ "com transação ativa.");
				}
			} catch (RuntimeException ex) {
				ex.printStackTrace();
			}
		}
	}

	public boolean isTransacaoAtiva() {
		EntityTransaction entityTransaction = threadTransaction.get();
		return (entityTransaction != null && entityTransaction.isActive());
	}

	private void alteraContador(int i) {
		Long count = threadCount.get();
		if (count == null) {
			count = 0L;
		}
		count += i;
		threadCount.set(count);
	}

	public boolean podeComitar() {
		Long count = threadCount.get();
		return (count == null || count == 0);
	}

	public void commitTransaction() {
		alteraContador(-1);
		if (!podeComitar()) {
			System.out.println("NÂO comitou transacao para="
					+ Thread.currentThread().getName());
			return;
		}
		EntityTransaction tx = threadTransaction.get();
		if (tx != null && tx.isActive()) {
			tx.commit();
			System.out.println("Comitou transacao para="
					+ Thread.currentThread().getName());
		}
		threadTransaction.set(null);
	}

	public void rollbackTransaction() {
		EntityTransaction entityTransaction = threadTransaction.get();
		try {
			threadTransaction.set(null);
			if (entityTransaction != null && entityTransaction.isActive()) {
				entityTransaction.rollback();
			}
		} catch (RuntimeException ex) {
			ex.printStackTrace();
		} finally {
			closeEntityManager();
		}
	}
}
